package org.fujene.memoryblock.blockwise;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.fujene.memoryblock.MemoryBlock;
import org.fujene.structure.Constants;
import org.fujene.structure.InvertIndexData;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class BlockwiseInvertIndexBlock extends MemoryBlock {
	private int opt_length = 0;

	public BlockwiseInvertIndexBlock(int bodySize, int ID, boolean isAllocate) {
		super(bodySize, ID, Constants.MEMORY_TYPE_INVINDEX, isAllocate);
	}

	// 相対ポインタ対応
	public InvertIndexData getInvertIndex(int ptr) {
		LookupPointer prevPtr, contentPtr;
		int termfreq;
		
		prevPtr = ByteConverter.getRelativePtr(getBody(ptr, RELPTR));
		if(prevPtr.equals(Constants.emptyRelativePtr))
			prevPtr = null;
		else
			prevPtr.block += this.getID();
		ptr += RELPTR;
		
		contentPtr = ByteConverter.getRelativePtr(getBody(ptr, RELPTR));
		if(contentPtr.equals(Constants.emptyRelativePtr))
			contentPtr = null;
		else
			contentPtr.block += this.getID();
		ptr += RELPTR;
		
		termfreq = ByteConverter.byteToInt(getBody(ptr, TERMFREQ));
		
		return new InvertIndexData(prevPtr, contentPtr, termfreq);
	}

	// 末尾に追加するのみ 相対ポインタ対応
	public LookupPointer setInvertIndex(LookupPointer prevPtr,
			LookupPointer docPtr, int termfreq) {
		int ptr = this.bodySize - this.bodyVacancy - (2 * RELPTR) - TERMFREQ;

		opt_length++;

		if(prevPtr != null && !prevPtr.equals(Constants.emptyPointer)){
			prevPtr.block -= this.getID();
			setBody(ByteConverter.setRelativePtr(prevPtr), ptr);
			prevPtr.block += this.getID();
		}else{
			setBody(ByteConverter.setRelativePtr(Constants.emptyRelativePtr), ptr);
		}
		ptr += RELPTR;
		
		if(docPtr != null){
			docPtr.block -= this.getID();
			setBody(ByteConverter.setRelativePtr(docPtr), ptr);
			docPtr.block += this.getID();
		}else{
			setBody(ByteConverter.setRelativePtr(Constants.emptyRelativePtr), ptr);
		}
		ptr += RELPTR;

		setBody(ByteConverter.intToByte(termfreq, TERMFREQ), ptr);
		
		return new LookupPointer(this.getID(), ptr - RELPTR - RELPTR);
	}
	
	public int getLeft() {
		int returnNum = this.bodyVacancy / (2 * RELPTR + TERMFREQ);
		
		if(returnNum > 0)
			this.bodyVacancy -= (2 * RELPTR + TERMFREQ);
		
		return returnNum;
	}
	
	public static byte[] createByteArray(LookupPointer prevPtr,
			LookupPointer docPtr, int termfreq) throws IOException{
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		
		stream.write(ByteConverter.setPtr(prevPtr));

		stream.write(ByteConverter.setPtr(docPtr));
		
		stream.write(ByteConverter.intToByte(termfreq, TERMFREQ));
		
		return stream.toByteArray();
	}
	
	public byte[] getData() throws IOException{
		ByteArrayOutputStream stream = new ByteArrayOutputStream(this.bodySize + 12); 
		
		stream.write(getOptionByteStream());
		stream.write(this.getBody(0, this.bodySize));
		
		return stream.toByteArray();
	}
	
	public void setData(byte[] array){
		opt_length = ByteConverter.byteToInt(array, 0, 4);
		
		setBody(array, 4, bodySize, 0);
	}
	
	@Override
	public int getOptionSize() {
		return 1;
	}
	
	@Override
	public byte[] getOptionByteStream() {
		return ByteConverter.intToByte(opt_length, 4);
	}
	
	@Override
	public void setOption(int option, int value) {
		if(option == 0) opt_length = value;
	}

	@Override
	public String getClassName() {
		return new String("InvertIndexBlock");
	}}
